//===============================================================================
// Microsoft patterns & practices Enterprise Library Contribution
// Resource Application Block
//===============================================================================

using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Common.Instrumentation;
using EntLibContrib.Resource.Providers;
#if !NUNIT
using Microsoft.VisualStudio.TestTools.UnitTesting;
#else
using NUnit.Framework;
using TestClass = NUnit.Framework.TestFixtureAttribute;
using TestInitialize = NUnit.Framework.SetUpAttribute;
using TestCleanup = NUnit.Framework.TearDownAttribute;
using TestMethod = NUnit.Framework.TestAttribute;
#endif

namespace EntLibContrib.Resource.Instrumentation.Tests
{
	[TestClass]
	public class ResourceInstrumentationAttachmentFixture
	{
		private MockResourceInstrumentationListener instrumentationListener;
		private ResourceInstrumentationProvider instrumentationProvider;
		private ResourceManagerFactoryHelper factoryHelper;
		private IResourceProvider resourceProvider;

		private const string instanceName = "resource";
		private const string key1 = "Ewdev";
		private const string key2 = "InvalidKey";
		private const string resourceAssemblyName = "EntLibContrib.Resource.TestStore";
		private const string resourceBaseName = "EntLibContrib.Resource.TestStore.Properties.Resources";

		[TestInitialize]
		public void SetUp ()
		{
			instrumentationProvider = new ResourceInstrumentationProvider();
			instrumentationListener = new MockResourceInstrumentationListener();

			ReflectionInstrumentationBinder binder = new ReflectionInstrumentationBinder();
			binder.Bind(instrumentationProvider, instrumentationListener);

			resourceProvider = new AssemblyResourceProvider(resourceAssemblyName, resourceBaseName);
			factoryHelper = new ResourceManagerFactoryHelper();
		}

		[TestMethod]
		public void ResourceInitializationDoesFireEvents ()
		{
			ResourceManager resourceManager = factoryHelper.BuildResourceManager(instanceName, resourceProvider, instrumentationProvider);

			Assert.AreEqual(1, instrumentationListener.eventArgs.Count);
			Assert.AreSame(typeof(ResourceInitializedEventArgs), instrumentationListener.eventArgs[0].GetType());
		}

		[TestMethod]
		public void ResourceAccessDoesFireEvents ()
		{
			ResourceManager resourceManager = factoryHelper.BuildResourceManager(instanceName, resourceProvider, instrumentationProvider);
			instrumentationListener.eventArgs.Clear();

			string resource = resourceManager[key1];
			Assert.AreEqual(1, instrumentationListener.eventArgs.Count);
			Assert.AreSame(typeof(ResourceAccessedEventArgs), instrumentationListener.eventArgs[0].GetType());
			Assert.AreEqual("Ewdev", ( (ResourceAccessedEventArgs)instrumentationListener.eventArgs[0] ).Key);
		}

		[TestMethod]
		[ExpectedException(typeof(ArgumentOutOfRangeException))]
		public void ResourceAccessWithInvalidKeyDoesFireEvents ()
		{
			ResourceManager resourceManager = factoryHelper.BuildResourceManager(instanceName, resourceProvider, instrumentationProvider);
			instrumentationListener.eventArgs.Clear();

			string resource = resourceManager[key2];
		}

		private IList<TArgs> FilterEventArgs<TArgs> (IEnumerable<EventArgs> sourceList) where TArgs : EventArgs
		{
			IList<TArgs> result = new List<TArgs>();

			foreach ( EventArgs arg in sourceList )
			{
				if ( arg is TArgs )
					result.Add(arg as TArgs);
			}

			return result;
		}

		private class MockResourceInstrumentationListener
		{
			public IList<EventArgs> eventArgs = new List<EventArgs>();

			[InstrumentationConsumer("ResourceInitialized")]
			public void ResourceInitialized (object sender, ResourceInitializedEventArgs args)
			{
				SaveEventArgs(args);
			}

			[InstrumentationConsumer("ResourceAccessed")]
			public void ResourceAccessed (object sender, ResourceAccessedEventArgs args)
			{
				SaveEventArgs(args);
			}

			[InstrumentationConsumer("ResourceFailed")]
			public void ResourceFailed (object sender, ResourceFailureEventArgs args)
			{
				SaveEventArgs(args);
			}

			private void SaveEventArgs (EventArgs args)
			{
				lock ( eventArgs )
				{
					eventArgs.Add(args);
				}
			}
		}
	}
}